package tripleheap;

import java.io.*;

import tripleheap.*;


import diskmgr.*;
import bufmgr.*;
import global.*;
import tripleheap.*;


interface  Filetype {
	int TEMP = 0;
	int ORDINARY = 1;

} 
public class TripleHeapfile implements Filetype,  GlobalConst {

	PageId      _firstDirPageId;   // page number of header page
	int         _ftype;
	private     boolean     _file_deleted;
	private     String 	 _fileName;
	private static int tempfilecount = 0;
	/**
	 * default Triple heap file
	 */
	public TripleHeapfile()
	{

	}

	private PageId get_file_entry(String filename)
	throws THFDiskMgrException {

		PageId tmpId = new PageId();

		try {
			tmpId = SystemDefs.JavabaseDB.get_file_entry(filename);
		}
		catch (Exception e) {
			throw new THFDiskMgrException(e,"Heapfile.java: get_file_entry() failed");
		}

		return tmpId;

	} // end of get_file_entry

	private void add_file_entry(String filename, PageId pageno)
	throws THFDiskMgrException {

		try {
			SystemDefs.JavabaseDB.add_file_entry(filename,pageno);
		}
		catch (Exception e) {
			throw new THFDiskMgrException(e,"Heapfile.java: add_file_entry() failed");
		}

	} // end of add_file_entry

	/**
	 * constructor for triple heap file
	 * @throws THFDiskMgrException 
	 * @throws IOException 
	 * @throws THFException 
	 * @throws THFBufMgrException 
	 * @throws HFBufMgrException 
	 */
	public TripleHeapfile(String name) throws THFDiskMgrException, IOException, THFException, THFBufMgrException, HFBufMgrException
	{
		// Give us a prayer of destructing cleanly if construction fails.
		_file_deleted = true;
		_fileName = null;

		if(name == null) 
		{
			// If the name is NULL, allocate a temporary name
			// and no logging is required.
			_fileName = "tempTripleHeapFile";
			String useId = new String("user.name");
			String userAccName;
			userAccName = System.getProperty(useId);
			_fileName = _fileName + userAccName;

			String filenum = Integer.toString(tempfilecount);
			_fileName = _fileName + filenum; 
			_ftype = TEMP;
			tempfilecount ++;

		}
		else
		{
			_fileName = name;
			_ftype = ORDINARY;    
		}

		// The constructor gets run in two different cases.
		// In the first case, the file is new and the header page
		// must be initialized.  This case is detected via a failure
		// in the db->get_file_entry() call.  In the second case, the
		// file already exists and all that must be done is to fetch
		// the header page into the buffer pool

		// try to open the file

		Page apage = new Page();
		_firstDirPageId = null;
		if (_ftype == ORDINARY)
			_firstDirPageId = get_file_entry(_fileName);

		if(_firstDirPageId==null)
		{
			// file doesn't exist. First create it.
			_firstDirPageId = newPage(apage, 1);
			// check error
			if(_firstDirPageId == null)
				throw new THFException(null, "can't new page");

			add_file_entry(_fileName, _firstDirPageId);
			// check error(new exception: Could not add file entry

			THFPage firstDirPage = new THFPage();
			firstDirPage.init(_firstDirPageId, apage);
			PageId pageId = new PageId(INVALID_PAGE);

			firstDirPage.setNextPage(pageId);
			firstDirPage.setPrevPage(pageId);
			unpinPage(_firstDirPageId, true /*dirty*/ );


		}
		_file_deleted = false;
		// ASSERTIONS:
		// - ALL private data members of class LabelHeapFile are valid:
		//
		//  - _firstDirPageId valid
		//  - _fileName valid
		//  - no datapage pinned yet    

	} // end of constructor 


	/**
	 * delete the Triple heap file
	 * @throws InvalidTripleSizeException 
	 */
	public void deleteFile()
	throws InvalidSlotNumberException, 
	FileAlreadyDeletedException, 
	InvalidTripleSizeException, 
	THFBufMgrException,
	THFDiskMgrException,
	IOException
	{
		if(_file_deleted ) 
			throw new FileAlreadyDeletedException(null, "file alread deleted");

		// Mark the deleted flag (even if it doesn't get all the way done).
		_file_deleted = true;

		// Deallocate all data pages
		PageId currentDirPageId = new PageId();
		currentDirPageId.pid = _firstDirPageId.pid;
		PageId nextDirPageId = new PageId();
		nextDirPageId.pid = 0;
		Page pageinbuffer = new Page();
		THFPage currentDirPage =  new THFPage();
		Triple atriple;

		pinPage(currentDirPageId, currentDirPage, false);

		TID tid = new TID();

		while(currentDirPageId.pid != INVALID_PAGE)
		{      
			for(tid = currentDirPage.firstTriple();
			tid != null;
			tid = currentDirPage.nextTriple(tid))
			{	
				atriple = currentDirPage.getTriple(tid);
				TDataPageInfo dpinfo = new TDataPageInfo( atriple);

				freePage(dpinfo.pageId);
			}
			// ASSERTIONS:
			// - we have freePage()'d all data pages referenced by the current directory page.

			nextDirPageId = currentDirPage.getNextPage();
			unpinPage(currentDirPageId, false);
			freePage(currentDirPageId);

			currentDirPageId.pid = nextDirPageId.pid;
			if (nextDirPageId.pid != INVALID_PAGE) 
			{
				pinPage(currentDirPageId, currentDirPage, false);
				//currentDirPage.openHFpage(pageinbuffer);
			}
		}

		delete_file_entry( _fileName );

	}
	/**
	 * Delete triple with given tid from the ﬁle
	 * @param tid
	 * @return
	 */
	public boolean deleteTriple(TID tid)
	throws InvalidSlotNumberException, 
	InvalidTripleSizeException, 
	THFException, 
	THFBufMgrException,
	THFDiskMgrException,
	Exception
	{
		boolean status;
		THFPage currentDirPage = new THFPage();
		PageId currentDirPageId = new PageId();
		THFPage currentDataPage = new THFPage();
		PageId currentDataPageId = new PageId();
		TID currentDataPageTid = new TID();

		status = _findDataPage(tid,currentDirPageId,currentDirPage,currentDataPageId,currentDataPage,currentDataPageTid);

		if(status != true) 
			return status;	// triple not found

		// ASSERTIONS:
		// - currentDirPage, currentDirPageId valid and pinned
		// - currentDataPage, currentDataPageid valid and pinned

		// get TDataPageInfo from the current directory page:
		Triple atriple;	

		atriple = currentDirPage.returnTriple(currentDataPageTid);
		TDataPageInfo pdpinfo = new TDataPageInfo(atriple);

		// delete the triple on the datapage
		currentDataPage.deleteTriple(tid);

		pdpinfo.recct--;
		pdpinfo.flushToTriple();	//Write to the buffer pool
		if (pdpinfo.recct >= 1) 
		{
			// more triples remain on datapage so it still hangs around.  
			// we just need to modify its directory entry

			pdpinfo.availspace = currentDataPage.available_space();
			pdpinfo.flushToTriple();
			unpinPage(currentDataPageId, true /* = DIRTY*/);

			unpinPage(currentDirPageId, true /* = DIRTY */);
		}
		else
		{
			// the triple is already deleted:
			// we're removing the last triple on datapage so free datapage
			// also, free the directory page if 
			//   a) it's not the first directory page, and 
			//   b) we've removed the last TDataPageInfo triple on it.

			// delete empty datapage: (does it get unpinned automatically? -NO, Ranjani)
			unpinPage(currentDataPageId, false /*undirty*/);

			freePage(currentDataPageId);

			// delete corresponding TDataPageInfo-entry on the directory page:
			// currentDataPageTid points to datapage (from for loop above)

			currentDirPage.deleteTriple(currentDataPageTid);

			// ASSERTIONS:
			// - currentDataPage, currentDataPageId invalid
			// - empty datapage unpinned and deleted

			// now check whether the directory page is empty:

			currentDataPageTid = currentDirPage.firstTriple();

			// st == OK: we still found a TDataPageInfo triple on this directory page
			PageId pageId;
			pageId = currentDirPage.getPrevPage();
			if((currentDataPageTid == null)&&(pageId.pid != INVALID_PAGE))
			{
				// the directory-page is not the first directory page and it is empty:
				// delete it

				// point previous page around deleted page:

				THFPage prevDirPage = new THFPage();
				pinPage(pageId, prevDirPage, false);

				pageId = currentDirPage.getNextPage();
				prevDirPage.setNextPage(pageId);
				pageId = currentDirPage.getPrevPage();
				unpinPage(pageId, true /* = DIRTY */);

				// set prevPage-pointer of next Page
				pageId = currentDirPage.getNextPage();
				if(pageId.pid != INVALID_PAGE)
				{
					THFPage nextDirPage = new THFPage();
					pageId = currentDirPage.getNextPage();
					pinPage(pageId, nextDirPage, false);

					//nextDirPage.openHFpage(apage);

					pageId = currentDirPage.getPrevPage();
					nextDirPage.setPrevPage(pageId);
					pageId = currentDirPage.getNextPage();
					unpinPage(pageId, true /* = DIRTY */);

				}

				// delete empty directory page: (automatically unpinned?)
				unpinPage(currentDirPageId, false/*undirty*/);
				freePage(currentDirPageId);
			}
			else
			{
				// either (the directory page has at least one more datapagetriple
				// entry) or (it is the first directory page):
				// in both cases we do not delete it, but we have to unpin it:

				unpinPage(currentDirPageId, true /* == DIRTY */);
			}
		}
		return true;
	}

	public TID searchTriple(byte[] tripleData) 
	throws THFException, Exception
	{
		int pagenou=Convert.getIntValue(0, tripleData);
		PageId currentDirPageId = new PageId(_firstDirPageId.pid);

		PageId nextDirPageId = new PageId(0);

		THFPage currentDirPage = new THFPage();
		THFPage currentDataPage = new THFPage();
		Page pageinbuffer = new Page();

		while(currentDirPageId.pid != INVALID_PAGE)
		{
			pinPage(currentDirPageId, currentDirPage, false);

			TID tid = new TID();
			Triple atriple;
			for (tid = currentDirPage.firstTriple();
			tid != null;	// tid==NULL means no more triple
			tid = currentDirPage.nextTriple(tid))
			{
				atriple = currentDirPage.getTriple(tid);
				TDataPageInfo dpinfo = new TDataPageInfo(atriple);
				pinPage(dpinfo.pageId, currentDataPage, false);

				TID currentTid = currentDataPage.firstTriple();
				Triple triple = currentDataPage.getTriple(currentTid);
				byte[] triplearray = triple.getTripleByteArray();


				while(currentTid != null)
				{
					String curTripleStr = Convert.getStrValue(0, triplearray, triplearray.length-8);
					String originalData = Convert.getStrValue(0, tripleData, tripleData.length-8);
					if(originalData.equals(curTripleStr))
					{
						double curConf = Convert.getDblValue(24, triplearray);
						double originalConf = Convert.getDblValue(24, tripleData);
						if(curConf <= originalConf)
						{
							unpinPage(dpinfo.pageId, false);
							unpinPage(currentDirPageId, false /*undirty*/);
							return currentTid;
						}
						else
						{
							boolean flag = deleteTriple(currentTid);
							unpinPage(dpinfo.pageId, false);
							unpinPage(currentDirPageId, false /*undirty*/);
							return null;
						}
					}
					currentTid = currentDataPage.nextTriple(currentTid);
				}
				unpinPage(dpinfo.pageId, false);
			}

			// ASSERTIONS: no more triple
			// - we have read all datapage triples on
			//   the current directory page.

			nextDirPageId = currentDirPage.getNextPage();
			unpinPage(currentDirPageId, false /*undirty*/);
			currentDirPageId.pid = nextDirPageId.pid;
		}

		// ASSERTIONS:
		// - if error, exceptions
		// - if end of tripleheapfile reached: currentDirPageId == INVALID_PAGE
		// - if not yet end of tripleheapfile: currentDirPageId valid

		return null;

	}
	/**
	 * Return number of triples in the ﬁle
	 * @return
	 * @throws  
	 */
	public int getTripleCnt()
	throws InvalidSlotNumberException, 
	InvalidTripleSizeException, 
	THFDiskMgrException,
	THFBufMgrException,
	IOException
	{
		int answer = 0;
		PageId currentDirPageId = new PageId(_firstDirPageId.pid);

		PageId nextDirPageId = new PageId(0);

		THFPage currentDirPage = new THFPage();
		Page pageinbuffer = new Page();

		while(currentDirPageId.pid != INVALID_PAGE)
		{
			pinPage(currentDirPageId, currentDirPage, false);

			TID tid = new TID();
			Triple atriple;
			for (tid = currentDirPage.firstTriple();
			tid != null;	// tid==NULL means no more triple
			tid = currentDirPage.nextTriple(tid))
			{
				atriple = currentDirPage.getTriple(tid);
				TDataPageInfo dpinfo = new TDataPageInfo(atriple);

				answer += dpinfo.recct;
			}

			// ASSERTIONS: no more triple
			// - we have read all datapage triples on
			//   the current directory page.

			nextDirPageId = currentDirPage.getNextPage();
			unpinPage(currentDirPageId, false /*undirty*/);
			currentDirPageId.pid = nextDirPageId.pid;
		}

		// ASSERTIONS:
		// - if error, exceptions
		// - if end of tripleheapfile reached: currentDirPageId == INVALID_PAGE
		// - if not yet end of tripleheapfile: currentDirPageId valid

		return answer;
	}

	/**
	 * Read the triple from ﬁle.
	 * @param tid
	 * @return
	 */
	public Triple getTriple(TID tid)
	throws InvalidSlotNumberException, 
	InvalidTripleSizeException, 
	THFException, 
	THFDiskMgrException,
	THFBufMgrException,
	Exception
	{
		boolean status;
		THFPage dirPage = new THFPage();
		PageId currentDirPageId = new PageId();
		THFPage dataPage = new THFPage();
		PageId currentDataPageId = new PageId();
		TID currentDataPageTid = new TID();

		status = _findDataPage(tid, currentDirPageId, dirPage, currentDataPageId, dataPage, currentDataPageTid);

		if(status != true) 
			return null; // triple not found 

		Triple atriple = new Triple();
		atriple = dataPage.getTriple(tid);

		/*
		 * getTriple has copied the contents of tid into triplePtr and fixed up
		 * tripleLen also.  We simply have to unpin dirpage and datapage which
		 * were originally pinned by _findDataPage.
		 */      
		unpinPage(currentDataPageId,false /*undirty*/);

		unpinPage(currentDirPageId,false /*undirty*/);

		return  atriple;  //(true?)OK, but the caller need check if atriple==NULL

	}

	/** Insert label into file, return its lid.
	 *
	 * @param recPtr pointer of the label
	 * @param recLen the length of the label
	 *
	 * @exception InvalidSlotNumberException invalid slot number
	 * @exception InvalidLabelSizeException invalid Label size
	 * @exception SpaceNotAvailableException no space left
	 * @exception LHFException heapfile exception
	 * @exception LHFBufMgrException exception thrown from bufmgr layer
	 * @exception LHFDiskMgrException exception thrown from diskmgr layer
	 * @exception IOException I/O errors
	 *
	 * @return the lid of the label
	 */
	public TID insertTriple(byte[] recPtr) 
	throws InvalidSlotNumberException,  
	InvalidTripleSizeException,
	SpaceNotAvailableException,
	THFException,
	THFBufMgrException,
	THFDiskMgrException,
	IOException
	{
		int dpinfoLen = 0;	
		int recLen = recPtr.length;
		boolean found;
		TID currentDataPageTid = new TID();
		Page pageinbuffer = new Page();
		THFPage currentDirPage = new THFPage();
		THFPage currentDataPage = new THFPage();

		THFPage nextDirPage = new THFPage(); 
		PageId currentDirPageId = new PageId(_firstDirPageId.pid);
		PageId nextDirPageId = new PageId();  // OK

		pinPage(currentDirPageId, currentDirPage, false/*Rdisk*/);

		found = false;
		Triple atriple;
		TDataPageInfo dpinfo = new TDataPageInfo();
		while (found == false)
		{ //Start While01
			// look for suitable dpinfo-struct
			for (currentDataPageTid = currentDirPage.firstTriple();
			currentDataPageTid != null;
			currentDataPageTid = 
				currentDirPage.nextTriple(currentDataPageTid))
			{
				atriple = currentDirPage.getTriple(currentDataPageTid);

				dpinfo = new TDataPageInfo(atriple);

				// need check the Triple length == DataPageInfo'slength

				if(recLen <= dpinfo.availspace)
				{
					found = true;
					break;
				}  
			}

			// two cases:
			// (1) found == true:
			//     currentDirPage has a datapageTriple which can accomodate
			//     the Triple which we have to insert
			// (2) found == false:
			//     there is no datapageTriple on the current directory page
			//     whose corresponding datapage has enough space free
			//     several subcases: see below
			if(found == false)
			{ //Start IF01
				// case (2)

				//System.out.println("no datapageTriple on the current directory is OK");
				//System.out.println("dirpage availspace "+currentDirPage.available_space());

				// on the current directory page is no datapageTriple which has
				// enough free space
				//
				// two cases:
				//
				// - (2.1) (currentDirPage->available_space() >= sizeof(DataPageInfo):
				//         if there is enough space on the current directory page
				//         to accomodate a new datapageTriple (type DataPageInfo),
				//         then insert a new DataPageInfo on the current directory
				//         page
				// - (2.2) (currentDirPage->available_space() <= sizeof(DataPageInfo):
				//         look at the next directory page, if necessary, create it.

				if(currentDirPage.available_space() >= dpinfo.size)
				{ 
					//Start IF02
					// case (2.1) : add a new data page Triple into the
					//              current directory page
					currentDataPage = _newDatapage(dpinfo); 
					// currentDataPage is pinned! and dpinfo->pageId is also locked
					// in the exclusive mode  

					// didn't check if currentDataPage==NULL, auto exception


					// currentDataPage is pinned: insert its Triple
					// calling a HFPage function



					atriple = dpinfo.convertToTriple();

					byte [] tmpData = atriple.getTripleByteArray();
					currentDataPageTid = currentDirPage.insertTriple(tmpData);

					TID tmprid = currentDirPage.firstTriple();


					// need catch error here!
					if(currentDataPageTid == null)
						throw new THFException(null, "no space to insert rec.");  

					// end the loop, because a new datapage with its Triple
					// in the current directorypage was created and inserted into
					// the TripleHeapFile; the new datapage has enough space for the
					// Triple which the user wants to insert

					found = true;

				} //end of IF02
				else
				{  //Start else 02
					// case (2.2)
					nextDirPageId = currentDirPage.getNextPage();
					// two sub-cases:
					//
					// (2.2.1) nextDirPageId != INVALID_PAGE:
					//         get the next directory page from the buffer manager
					//         and do another look
					// (2.2.2) nextDirPageId == INVALID_PAGE:
					//         append a new directory page at the end of the current
					//         page and then do another loop

					if (nextDirPageId.pid != INVALID_PAGE) 
					{ //Start IF03
						// case (2.2.1): there is another directory page:
						unpinPage(currentDirPageId, false);

						currentDirPageId.pid = nextDirPageId.pid;

						pinPage(currentDirPageId,
								currentDirPage, false);



						// now go back to the beginning of the outer while-loop and
						// search on the current directory page for a suitable datapage
					} //End of IF03
					else
					{  //Start Else03
						// case (2.2): append a new directory page after currentDirPage
						//             since it is the last directory page
						nextDirPageId = newPage(pageinbuffer, 1);
						// need check error!
						if(nextDirPageId == null)
							throw new THFException(null, "can't new pae");

						// initialize new directory page
						nextDirPage.init(nextDirPageId, pageinbuffer);
						PageId temppid = new PageId(INVALID_PAGE);
						nextDirPage.setNextPage(temppid);
						nextDirPage.setPrevPage(currentDirPageId);

						// update current directory page and unpin it
						// currentDirPage is already locked in the Exclusive mode
						currentDirPage.setNextPage(nextDirPageId);
						unpinPage(currentDirPageId, true/*dirty*/);

						currentDirPageId.pid = nextDirPageId.pid;
						currentDirPage = new THFPage(nextDirPage);

						// remark that MINIBASE_BM->newPage already
						// pinned the new directory page!
						// Now back to the beginning of the while-loop, using the
						// newly created directory page.

					} //End of else03
				} // End of else02
				// ASSERTIONS:
				// - if found == true: search will end and see assertions below
				// - if found == false: currentDirPage, currentDirPageId
				//   valid and pinned

			}//end IF01
			else
			{ //Start else01
				// found == true:
				// we have found a datapage with enough space,
				// but we have not yet pinned the datapage:

				// ASSERTIONS:
				// - dpinfo valid

				// System.out.println("find the dirpageTriple on current page");

				pinPage(dpinfo.pageId, currentDataPage, false);
				//currentDataPage.openHFpage(pageinbuffer);


			}//End else01
		} //end of While01

		// ASSERTIONS:
		// - currentDirPageId, currentDirPage valid and pinned
		// - dpinfo.pageId, currentDataPagelid valid
		// - currentDataPage is pinned!

		if ((dpinfo.pageId).pid == INVALID_PAGE) // check error!
			throw new THFException(null, "invalid PageId");

		if (!(currentDataPage.available_space() >= recLen))
			throw new SpaceNotAvailableException(null, "no available space");

		if (currentDataPage == null)
			throw new THFException(null, "can't find Data page");


		TID tid;
		tid = currentDataPage.insertTriple(recPtr);

		dpinfo.recct++;
		dpinfo.availspace = currentDataPage.available_space();


		unpinPage(dpinfo.pageId, true /* = DIRTY */);

		// DataPage is now released
		atriple = currentDirPage.returnTriple(currentDataPageTid);
		TDataPageInfo dpinfo_ondirpage = new TDataPageInfo(atriple);


		dpinfo_ondirpage.availspace = dpinfo.availspace;
		dpinfo_ondirpage.recct = dpinfo.recct;
		dpinfo_ondirpage.pageId.pid = dpinfo.pageId.pid;
		dpinfo_ondirpage.flushToTriple();


		unpinPage(currentDirPageId, true /* = DIRTY */);


		return tid;

	}


	/**
	 * Initiate a sequential scan
	 * @return
	 */
	public TScan openScan()
	throws InvalidTripleSizeException,
	IOException
	{
		TScan newscan = new TScan(this);
		return newscan;
	}

	/** Updates the specified triple in the tripleheapfile.
	 * @param tid: the triple which needs update
	 * @param newtriple: the new content of the triple
	 *
	 * @exception InvalidSlotNumberException invalid slot number
	 * @exception InvalidUpdateException invalid update on triple
	 * @exception InvalidTripleSizeException invalid triple size
	 * @exception THFException tripleheapfile exception
	 * @exception THFBufMgrException exception thrown from bufmgr layer
	 * @exception THFDiskMgrException exception thrown from diskmgr layer
	 * @exception Exception other exception
	 * @return ture:update success   false: can't find the triple
	 */
	public boolean updateTriple(TID tid, Triple newTriple)throws InvalidSlotNumberException, 
	InvalidUpdateException, 
	InvalidTripleSizeException,
	THFException, 
	THFDiskMgrException,
	THFBufMgrException,
	Exception
	{
		boolean status;
		THFPage dirPage = new THFPage();
		PageId currentDirPageId = new PageId();
		THFPage dataPage = new THFPage();
		PageId currentDataPageId = new PageId();
		TID currentDataPageTid = new TID();

		status = _findDataPage(tid,
				currentDirPageId, dirPage, 
				currentDataPageId, dataPage,
				currentDataPageTid);

		if(status != true) return status;	// triple not found
		Triple atriple = new Triple();
		atriple = dataPage.returnTriple(tid);

		// Assume update a triple with a triple whose length is equal to
		// the original triple

		if(newTriple.getLength() != atriple.getLength())
		{
			unpinPage(currentDataPageId, false /*undirty*/);
			unpinPage(currentDirPageId, false /*undirty*/);

			throw new InvalidUpdateException(null, "invalid triple update");

		}

		// new copy of this triple fits in old space;
		atriple.tripleCopy(newTriple);
		unpinPage(currentDataPageId, true /* = DIRTY */);

		unpinPage(currentDirPageId, false /*undirty*/);      
		return true;
	}

	//private methods

	/**
	 * short cut to access the pinPage function in bufmgr package.
	 * @see bufmgr.pinPage
	 */
	private void pinPage(PageId pageno, Page page, boolean emptyPage) throws THFBufMgrException 
	{ 		
		try {
			SystemDefs.JavabaseBM.pinPage(pageno, page, emptyPage);
		}
		catch (Exception e) {
			throw new THFBufMgrException(e,"TripleHeapfile.java: pinPage() failed");
		}

	} 

	/**
	 * short cut to access the unpinPage function in bufmgr package.
	 * @see bufmgr.unpinPage
	 */
	private void unpinPage(PageId pageno, boolean dirty) throws THFBufMgrException 
	{
		try {
			SystemDefs.JavabaseBM.unpinPage(pageno, dirty);
		}
		catch (Exception e) {
			throw new THFBufMgrException(e,"TripleHeapfile.java: unpinPage() failed");
		}
	}

	private void delete_file_entry(String filename) throws THFDiskMgrException
	{
		try {
			SystemDefs.JavabaseDB.delete_file_entry(filename);
		}
		catch (Exception e) {
			throw new THFDiskMgrException(e,"TripleHeapfile.java: delete_file_entry() failed");
		}
	}

	private void freePage(PageId pageno) throws THFBufMgrException
	{
		try {
			SystemDefs.JavabaseBM.freePage(pageno);
		}
		catch (Exception e) {
			throw new THFBufMgrException(e,"TripleHeapfile.java: freePage() failed");
		}

	}

	/** Internal TripleHeapFile function (used in getTriple and updateTriple):
	 *  returns pinned directory page and pinned data page of the specified 
	 *  user triple(tid) and true if triple is found.
	 *  If the user triple cannot be found, return false.
	 */
	private boolean  _findDataPage( TID tid,
			PageId dirPageId, THFPage dirpage,
			PageId dataPageId, THFPage datapage,
			TID rpDataPageTid) 
	throws InvalidSlotNumberException, 
	InvalidTripleSizeException, 
	THFException,
	THFBufMgrException,
	THFDiskMgrException,
	Exception
	{
		PageId currentDirPageId = new PageId(_firstDirPageId.pid);

		THFPage currentDirPage = new THFPage();
		THFPage currentDataPage = new THFPage();
		TID currentDataPageTid = new TID();
		PageId nextDirPageId = new PageId();
		// datapageId is stored in dpinfo.pageId 	      
		pinPage(currentDirPageId, currentDirPage, false/*read disk*/);

		Triple atriple = new Triple();
		while (currentDirPageId.pid != INVALID_PAGE)
		{		// Start While01
			// ASSERTIONS:
			//  currentDirPage, currentDirPageId valid and pinned and Locked.

			for( currentDataPageTid = currentDirPage.firstTriple(); currentDataPageTid != null;
			currentDataPageTid = currentDirPage.nextTriple(currentDataPageTid))
			{
				try{
					atriple = currentDirPage.getTriple(currentDataPageTid);
				}
				catch (InvalidSlotNumberException e)// check error! return false(done) 
				{
					return false;
				}

				TDataPageInfo dpinfo = new TDataPageInfo(atriple);
				try{
					pinPage(dpinfo.pageId, currentDataPage, false/*Rddisk*/);
					//check error;need unpin currentDirPage
				}catch (Exception e)
				{
					unpinPage(currentDirPageId, false/*undirty*/);
					dirpage = null;
					datapage = null;
					throw e;
				}
				// ASSERTIONS:
				// - currentDataPage, currentDataPageTid, dpinfo valid
				// - currentDataPage pinned

				if(dpinfo.pageId.pid==tid.pageNo.pid)
				{
					atriple = currentDataPage.returnTriple(tid);
					// found user's triple on the current datapage which itself
					// is indexed on the current dirpage.  Return both of these.
					dirpage.setpage(currentDirPage.getpage());
					dirPageId.pid = currentDirPageId.pid;
					datapage.setpage(currentDataPage.getpage());
					dataPageId.pid = dpinfo.pageId.pid;

					rpDataPageTid.pageNo.pid = currentDataPageTid.pageNo.pid;
					rpDataPageTid.slotNo = currentDataPageTid.slotNo;
					return true;
				}
				else
				{
					// user triple not found on this datapage; unpin it
					// and try the next one
					unpinPage(dpinfo.pageId, false /*undirty*/);		  
				}
			}
			// if we would have found the correct datapage on the current
			// directory page we would have already returned.
			// therefore:
			// read in next directory page:	  
			nextDirPageId = currentDirPage.getNextPage();
			try{
				unpinPage(currentDirPageId, false /*undirty*/);
			}
			catch(Exception e) {
				throw new THFException (e, "tripleheapfile,_find,unpinpage failed");
			}

			currentDirPageId.pid = nextDirPageId.pid;
			if(currentDirPageId.pid != INVALID_PAGE)
			{
				pinPage(currentDirPageId, currentDirPage, false/*Rdisk*/);
				if(currentDirPage == null)
					throw new THFException(null, "pinPage return null page");  
			}	  
		} // end of While01
		// checked all dir pages and all data pages; user triple not found:(
		dirPageId.pid = dataPageId.pid = INVALID_PAGE;
		return false;   
	}

	/* get a new datapage from the buffer manager and initialize dpinfo
    @param dpinfop the information in the new THFPage
	 */
	private THFPage _newDatapage(TDataPageInfo dpinfop)
	throws THFException,
	THFBufMgrException,
	THFDiskMgrException,
	IOException, 
	THFBufMgrException
	{
		Page apage = new Page();
		PageId pageId = new PageId();
		pageId = newPage(apage, 1);

		if(pageId == null)
			throw new THFException(null, "can't new pae");

		// initialize internal values of the new page:   
		THFPage thfpage = new THFPage();
		thfpage.init(pageId, apage);

		dpinfop.pageId.pid = pageId.pid;
		dpinfop.recct = 0;
		dpinfop.availspace = thfpage.available_space();

		return thfpage;

	} // end of _newDatapage

	private PageId newPage(Page page, int num)
	throws THFBufMgrException 
	{
		PageId tmpId = new PageId();
		try {
			tmpId = SystemDefs.JavabaseBM.newPage(page,num);
		}
		catch (Exception e) {
			throw new THFBufMgrException(e,"TripleHeapfile.java: newPage() failed");
		}
		return tmpId;

	} // end of newPage
}